// 
// ShaderManager.cs
//  
// Author:
//       Tomas Vondracek <tomas.vondracek@gmail.com>
// 
// Copyright (c) 2009 Tomas Vondracek
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using System.IO;
using System.Collections.Generic;
using OpenTK.Graphics;
using OpenTK;
//using OpenTK.Math;

namespace Game
{

	struct ShaderInfo
	{
		public int vertexShaderHandle,
            fragmentShaderHandle,
            shaderProgramHandle,
            modelviewMatrixLocation,
            projectionMatrixLocation,
            positionVboHandle,
            normalVboHandle,
            indicesVboHandle;
		
        public OpenTK.Math.Matrix4 projectionMatrix, modelviewMatrix;
	}

	public class ShaderManager
	{
		Dictionary<string, string> shaders;
		
		 int vertexShaderHandle,
            fragmentShaderHandle,
            shaderProgramHandle,
            modelviewMatrixLocation,
            projectionMatrixLocation,
            positionVboHandle,
            normalVboHandle,
            indicesVboHandle;
		
        Matrix4 projectionMatrix, modelviewMatrix;

        public int ShaderProgramHandle {
			get {
				return shaderProgramHandle;
			}
		}		
		public ShaderManager ()
		{
			this.shaders = new Dictionary<string, string>();
		}
		
		public void LoadShader(string path)
		{
			FileInfo info = new FileInfo(path);
			TextReader reader = new StreamReader(path);
			
			string source = reader.ReadToEnd();
			string name = info.Name;
			
			if (!this.shaders.ContainsKey(name))
			{
				this.shaders.Add(name, source);
			}
			else
			{
				Logging.Logger.AddInfo(string.Format("Shader {0} from {1} already loaded", name, path));
			}
		}
		
		public void CreateShaders()
        {
            vertexShaderHandle = GL.CreateShader( ShaderType.VertexShader );
            fragmentShaderHandle = GL.CreateShader( ShaderType.FragmentShader );
 
            GL.ShaderSource( vertexShaderHandle, this.shaders["basic_vertex_shader.fx"] );
            GL.ShaderSource( fragmentShaderHandle, this.shaders["basic_fragment_shader.fx"] );
 
            GL.CompileShader( vertexShaderHandle );
            GL.CompileShader( fragmentShaderHandle );
        }
		
		public void CreateProgram()
        {
            shaderProgramHandle = GL.CreateProgram();
 
            GL.AttachShader( shaderProgramHandle, vertexShaderHandle );
            GL.AttachShader( shaderProgramHandle, fragmentShaderHandle );
 
            GL.LinkProgram( shaderProgramHandle );
 
            string programInfoLog;
            GL.GetProgramInfoLog(shaderProgramHandle, out programInfoLog);

            Logging.Logger.AddImportant(programInfoLog);
            GL.UseProgram(shaderProgramHandle);
        }
		
		public void QueryMatrixLocations()
        {
            projectionMatrixLocation = GL.GetUniformLocation( shaderProgramHandle, "projection_matrix" );
            modelviewMatrixLocation = GL.GetUniformLocation( shaderProgramHandle, "modelview_matrix" );
        }
 
        public void SetModelviewMatrix( Matrix4 matrix )
        {
            modelviewMatrix = matrix;
            //GL.UniformMatrix4( modelviewMatrixLocation, false, ref modelviewMatrix );
        }
 
        public void SetProjectionMatrix( Matrix4 matrix )
        {
            projectionMatrix = matrix;
           // GL.UniformMatrix4( projectionMatrixLocation, false, ref projectionMatrix );
        }
 
        public void LoadVertexPositions()
        {
            //GL.GenBuffers( 1, out positionVboHandle );
            //GL.BindBuffer( BufferTarget.ArrayBuffer, positionVboHandle );
            //GL.BufferData<Vector3>( BufferTarget.ArrayBuffer,
            //    new IntPtr( positionVboData.Length * Vector3.SizeInBytes ),
            //    positionVboData, BufferUsageHint.StaticDraw );
 
            //GL.EnableVertexAttribArray( 0 );
            //GL.BindAttribLocation( shaderProgramHandle, 0, "vertex_position" );
            //GL.VertexAttribPointer( 0, 3, VertexAttribPointerType.Float, false, Vector3.SizeInBytes, 0 );            
        }
 
        public void LoadVertexNormals()
        {
            //GL.GenBuffers( 1, out normalVboHandle );
            //GL.BindBuffer( BufferTarget.ArrayBuffer, normalVboHandle );
            //GL.BufferData<Vector3>( BufferTarget.ArrayBuffer,
            //    new IntPtr( positionVboData.Length * Vector3.SizeInBytes ),
            //    positionVboData, BufferUsageHint.StaticDraw );
 
            //GL.EnableVertexAttribArray( 1 );            
            //GL.BindAttribLocation( shaderProgramHandle, 1, "vertex_normal" );            
            //GL.VertexAttribPointer( 1, 3, VertexAttribPointerType.Float, false, Vector3.SizeInBytes, 0 );
        }
	}
}
